
/**
 *
 *        @param obj 待查询json对象
 *        obj可以是两种格式
 *        {title:['a1','b1','c1'],data:[{a,b,c},{a,b,c},....]}
 *        {data:[{a1:a,b1:b,c1:c}]}
 *        其中a1，b1,c1为查询字段
 *
 *        eq：
 *        var jsonq=new Q(obj);
 *        jsonq.query("A @@ 中").update({A:5});
 *        jsonq.query("b > 1").del();
 *        jsonq.add({A:5,B:6});
 */
function Q(obj){
    if(!obj.title && !obj.data)return null;
    if(isArr(obj.data) && !obj.title){
        obj.title=function(){
            var arr=[];
            for(var i in obj.data[0]){
                arr.push(i);
            }
            return arr;
        }();
    }

    if(obj.title.indexOf(this.indexStr)==-1){
        obj.title.push(this.indexStr);
    }
    if(isArr(obj.data) &&  obj.data.length>0){
        var tmparrData=[],tmparrData2,i,k;
        if(!isObject(obj.data[0])){
            for(i=0;i<obj.data.length;i++){
                tmparrData2={};
                if(typeof obj.data[i]=='string'){
                    tmparrData2[obj.title[0]]=obj.data[i];
                }else{
                    for(k=0;k<obj.data[i].length;k++){
                        tmparrData2[obj.title[k]]=obj.data[i][k];
                    }
                }
                tmparrData2[this.indexStr]=i+1;
                tmparrData.push(tmparrData2);
            }
        }else{
            if(obj.data[0][this.indexStr]){
                throw '对象不能含有'+this.indexStr+'字段';
                return null;
            }
            for(i=0;i<obj.data.length;i++){
                obj.data[i].INDEX=i+1
            }
            tmparrData=obj.data;
        }
    }
    this.data=obj.data=tmparrData;
    this.currentData=tmparrData;
    this.title=obj.title;
}
Q.prototype.currentData=[];//当前操作数据结果
Q.prototype.title=[];//字段列表
Q.prototype.data=[];//原始数据
Q.prototype.indexStr='_INDEX_';//自增字段名


/**
 * 获取查询结果
 * @returns {*|Array}
 */
Q.prototype.get=function(){
    return cloneData(this.currentData);
};

/**
 * 查询数据
 * @param condition  查询条件是js表达式 不同使用()
 * @param count 返回条数 有利于提高性能
 * 表达式含义 先以||分隔，各子条件集是逻辑或关系，各子条件再按&&分隔，其子条件是逻辑与关系
 * && 逻辑与
 * || 逻辑或
 * == 等于
 * >=大于等于
 * <=小于等于
 * !=不等于
 * @@包含
 * !@不包含
 * @@@反包含
 * >大于
 * <小于
 * REX 正则表达式
 * FUNC 自定义函数
 * @return 查询对象
 */
Q.prototype.query=function(condition,count){
    condition=parseCondition(condition);
    if(condition.length==0)return this;
    var data2=[],tmpcount=0,m,n,o,is,value;
    for(var a=0;a<this.data.length;a++){
        is=true;
        for(m=0;m<condition.length;m++){
            is=true;
            for(n=0;n<condition[m].length;n++){
                o=condition[m][n];
                if(typeof o[2]=="function"){
                    value=o[2];
                }else if(this.title.indexOf(o[2])>-1){
                    value=this.data[a][o[2]];
                }else{
                    value=o[2];
                }
                if(o[1]=="==" && this.data[a][o[0]]!=value){
                    is=false;
                }else if(o[1]==">" && this.data[a][o[0]]<=value){
                    is=false;
                }else if(o[1]==">=" && this.data[a][o[0]]<value){
                    is=false;
                }else if(o[1]=="<=" && this.data[a][o[0]]>value){
                    is=false;
                }else if(o[1]=="<" && this.data[a][o[0]]>=value) {
                    is = false;
                }else if(o[1]=="!=" && this.data[a][o[0]]==value){
                    is=false;
                }else if(o[1]=="@@" && this.data[a][o[0]].toString().indexOf(value)==-1) {
                    is = false;
                }else if(o[1]=="!@" && this.data[a][o[0]].toString().indexOf(value)!=-1){
                    is=false;
                }else if(o[1]=="@@@" && value.indexOf(this.data[a][o[0]])==-1){
                    is=false;
                }else if(o[1]=="REX" && this.data[a][o[0]].toString().search(value)==-1){
                    is=false;
                }else if(o[1]=="FUNC" && value(this.data[a][o[0]])){
                    is=false;
                }
                if(!is)break;
            }
            if(is)break;
        }
        if(is){
            data2.push(this.data[a]);
            tmpcount++;
            if(count && tmpcount>=count)break;
        }
    }
    this.currentData=cloneData(data2);
    return this;
}

/**
 * 对结果集进行二次查询
 * @param condition 同query方法
 * @param count 同query方法
 * @returns {返回新的查询对象}
 */
Q.prototype.query2=function(condition,count){
    var queryObj=new Q({
        title:this.title,
        data:this.currentData
    });
    return queryObj.query(condition,count);
}


/**
 * 数据分页
 * @param start 开始位置
 * @param count 返回总条数，不存在时start=0，count=start
 * @return 查询对象
 */
Q.prototype.limit=function(start,count){
    if(!start)return this;
    var data=[];
    if(!count){
        count=start;
        start=0;
    }
    for(start;start<count;start++){
        data.push(this.currentData[start]);
    }
    this.currentData=data;
    return this;
}

/**
 *
 * @param field 排序字段名默认 this.indexStr
 * @param sortMode 排序方式 desc/asc默认
 */
Q.prototype.order=function(sortMode,field){
    if(!field)field=this.indexStr;
    sortMode=sortMode!='desc'?"asc":sortMode;
    this.currentData.sort(function(a,b){
        if(sortMode=='asc'){
            return a[field]>b[field]?true:false;
        }else{
            return a[field]<b[field]?true:false;
        }
    });
    return this;
}

/**
 * 更新数据
 * @param kvArr 键值对
 * @returns 返回查询对象
 */

Q.prototype.update=function(kvArr){
    if(!isObject(kvArr)){
        throw "参数不是键值对";
        return this;
    }
    var key,m,oldData;
    for(var i=0;i<this.currentData.length;i++){
        for(m=0;m<this.data.length;m++){
            if(this.data[m][this.indexStr]==this.currentData[i][this.indexStr]){
                oldData=this.data[m];
                break;
            }
        }
        for(key in kvArr){
            if(key==this.indexStr)continue;
            this.currentData[i][key]=kvArr[key];
            oldData[key]=kvArr[key];
        }
        oldData={};
    }
    return this;
}

/**
 * 删除数据
 * @returns 返回查询对象
 */
Q.prototype.del=function(){
    var a,i,tmp=[];
    for(a=0;a<this.currentData.length;a++){
        for(i=0;i<this.data.length;i++){
            if(this.currentData[a][this.indexStr]==this.data[i][this.indexStr]){
                this.data.splice(i,1);
                break;
            }
        }
    }
    this.currentData=[];
    return this;
}

/**
 * 添加数据 不能用于链接写法
 * @kvArr 键值对
 * @returns 返回查询对象
 */
Q.prototype.add=function(kvArr){
    var index=this.max(this.indexStr,this.data)[0],arr=[];
    kvArr[this.indexStr]=index+1;
    for(var key in kvArr){
        arr[this.title.indexOf(key)]=kvArr[key];
    }
    this.data.push(arr);
    return this;
}

/**
 *
 * @param field 字段名
 * @returns {[最大值,对应行数据]}
 */
Q.prototype.max=function(field,data){
    var record=0;
    if(!data)data=this.currentData;
    for(var i=0;i<data.length;i++){

        if(data[i][field]>data[record][field]){
            record=i;
        }
    }
    return [data[record][field],data[record]];
}
/**
 *
 * @param field 字段名
 * @returns {[最小值,对应行数据]}
 */
Q.prototype.min=function(field,data){
    var record=0;
    if(!data)data=this.currentData;
    for(var i=0;i<data.length;i++){
        if(data[i][field]<data[record][field]){
            record=i;
        }
    }
    return [data[record][field],data[record]];
}

/**
 * 计算合值
 * @param field 字段名
 * @returns 合值
 */
Q.prototype.sub=function(field){
    var record=0;
    if(this.currentData.length>0 && !isNaN(this.data[0]))return 0;
    for(var i=0;i<this.currentData.length;i++){
        record+=parseFloat(this.currentData[record][field]);
    }
    return record;
}
/**
 * 遍历查询结果
 * @param callback
 */
Q.prototype.each=function(callback){
    var data=this.currentData,res;
    if(data.length==0)data=this.data;
    if(callback) {
        for(var i=0;i<data.length;i++){
            res=callback(data[i],i);
            if(res==true){
                continue;
            }else if(res==false){
                break;
            }
        }
    }
    return this;
}

/**
 * 计算平均值
 * @param field 字段名
 * @returns 平均值
 */
function average(field){
    var record=0;
    if(this.data.length>0 && !isNaN(this.data[0]))return 0;
    for(var i=0;i<this.currentData.length;i++){
        record+=this.currentData[record][field];
    }
    return record/this.currentData.length;
}

/**
 * 内部函数，生成查询条件数据
 * @param str
 * @returns {Array}
 */
function parseCondition(str){
    str=str.replace(/\s/g,"");
    var tmp=[],tmp2,tmp3,res=[],i,k,m,f;
    str=str.split('||');
    for(i=0;i<str.length;i++){
        if(str[i]){
            tmp.push(str[i]);
        }
    }

    for(i=0;i<tmp.length;i++) {
        tmp2 = tmp[i].split('&&');
        tmp3=[];

        for (k=0;k<tmp2.length;k++){
            f="";
            if(tmp2[k]){
                tmp2[k].replace(/(==|>=|<=|!=|@@@|@@|>|<|REX|FUNC)/g,function(word){
                    f=word;
                    return word;
                });
                if(!f)continue;
                m=tmp2[k].split(f);
                try{
                    if (f == "REX"){
                        m[1] = new RegExp(m[1], "g")
                    }else if(f == "REX"){
                        m[1] = eval(m[1]);
                    }
                }catch (e){
                    throw '数据查询正则规则错误';
                    return [];
                }
                tmp3.push([m[0], f, m[1]]);
            }
        }
        if(tmp3.length>0)res.push(tmp3);
    }
    return res;
}

/**
 * 判断是否是数组
 * @type {Q}
 */
function isArr(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
}
/**
 * 判断是否是对象
 * @type {Q}
 */
function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
}

/**
 * 复制数据
 * @param data
 * @returns {Array}
 */
function cloneData(data){
    var arr=[],tmp,k;
    for(var i=0;i<data.length;i++){
        tmp={};
        for(k in data[i]){
            tmp[k]=data[i][k];
        }
        arr.push(tmp);
    }
    return arr;
}
module.exports=Q;
